from datetime import datetime
from typing import Optional, Tuple, Type, Union
from db import models
from sqlalchemy.orm import Session
from sqlalchemy import or_
from schemas.article import CreateArticleRequest, UpdateArticleRequest, DeleteArticleRequest, \
    CreateArticleCommentRequest, LikeArticleCommentRequest


class Article:
    @staticmethod
    def create(db: Session, data: CreateArticleRequest) -> models.Article:
        item = models.Article(
            created_on=data.created_on,
            created_by=data.created_by,
            title=data.title,
            abstract=data.abstract,
            content=data.content,
            tags=data.tags,
            author=data.author,
            avatar=data.avatar,
            cover=data.cover,
        )
        db.add(item)
        db.commit()
        return item

    @staticmethod
    def get(db: Session, article_id: int) -> Union[models.Article, None]:
        return db.query(models.Article).get(article_id)

    @staticmethod
    def gets(db: Session,
             page: int,
             page_size: int,
             kw: Optional[str] = None) -> Tuple[int, list[Type[models.Article]]]:
        if kw is None:
            count = db.query(models.Article).filter_by(status=1).count()

            data = db.query(models.Article).filter_by(status=1).offset(page * page_size).limit(page_size).all()
        else:
            count = db.query(models.Article).filter_by(status=1).filter(
                or_(
                    models.Article.title.like(f"%{kw}%"),
                    models.Article.abstract.like(f"%{kw}%")
                )
            ).count()

            data = db.query(models.Article).filter_by(status=1).filter(
                or_(
                    models.Article.title.like(f"%{kw}%"),
                    models.Article.abstract.like(f"%{kw}%")
                )
            ).offset(page * page_size).limit(page_size).all()
        return count, data

    @staticmethod
    def update(db: Session, data: UpdateArticleRequest) -> None:
        db.query(models.Article).filter_by(id=data.id).update({
            "updated_on": data.updated_on,
            "updated_by": data.updated_by,
            "title": data.title,
            "abstract": data.abstract,
            "content": data.content,
            "tags": data.tags,
            "author": data.author,
            "avatar": data.avatar,
            "cover": data.cover,
        })
        db.commit()

    @staticmethod
    def delete(db: Session, data: DeleteArticleRequest) -> None:
        db.query(models.Article).filter_by(id=data.id).update({
            "status": 0,
            "updated_on": data.updated_on,
            "updated_by": data.updated_by,
        })
        db.commit()

    @staticmethod
    def add_like(db: Session, article_id: int):
        item = db.query(models.Article).get(article_id)
        if item is not None:
            item.likes_count += 1
            db.commit()

    @staticmethod
    def subtract_like(db: Session, article_id: int):
        item = db.query(models.Article).get(article_id)
        if item is not None:
            if item.likes_count > 0:
                item.likes_count -= 1
            db.commit()


class ArticleLike:
    @staticmethod
    def create(db: Session, customer_id: int, article_id: int) -> models.ArticleLike:
        item = models.ArticleLike(
            created_on=datetime.now(),
            customer_id=customer_id,
            article_id=article_id
        )
        db.add(item)
        db.commit()
        return item

    @staticmethod
    def delete(db: Session, customer_id: int, article_id: int):
        db.query(models.ArticleLike).filter_by(customer_id=customer_id, article_id=article_id).delete()
        db.commit()

    @staticmethod
    def get_by_customer(db: Session, customer_id: int):
        return db.query(models.ArticleLike).filter_by(customer_id=customer_id, status=1).all()


class ArticleComment:
    @staticmethod
    def create(db: Session, data: CreateArticleCommentRequest) -> models.ArticleComment:
        item = models.ArticleComment(
            created_on=datetime.now(),
            customer_id=data.customer_id,
            article_id=data.article_id,
            parent_id=data.parent_id,
            content=data.content
        )
        db.add(item)
        db.commit()
        return item

    @staticmethod
    def get_by_article_id(db: Session, article_id: int):
        return db.query(models.ArticleComment).filter_by(article_id=article_id, status=1).all()

    @staticmethod
    def add_like(db: Session, comment_id: int):
        item = db.query(models.ArticleComment).get(comment_id)
        if item is not None:
            item.likes_count += 1

            db.commit()

    @staticmethod
    def subtract_like(db: Session, comment_id: int):
        item = db.query(models.ArticleComment).get(comment_id)
        if item is not None:
            if item.likes_count > 0:
                item.likes_count -= 1

            db.commit()

    @staticmethod
    def count_by_article(db: Session, article_id: int) -> int:
        return db.query(models.ArticleComment).filter_by(article_id=article_id, status=1).count()


class ArticleCommentLike:
    @staticmethod
    def create(db: Session, data: LikeArticleCommentRequest) -> models.ArticleComment:
        item = models.ArticleCommentLike(
            created_on=datetime.now(),
            customer_id=data.customer_id,
            comment_id=data.comment_id,
        )
        db.add(item)
        db.commit()
        return item

    @staticmethod
    def delete(db: Session, customer_id: int, comment_id: int):
        db.query(models.ArticleCommentLike).filter_by(customer_id=customer_id, comment_id=comment_id).delete()
        db.commit()

    @staticmethod
    def get_by_customer(db: Session, customer_id: int):
        return db.query(models.ArticleCommentLike).filter_by(customer_id=customer_id, status=1).all()
